﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Drawing.Design;
using System.Windows.Forms.VisualStyles;
using wyDay.Controls;

namespace AngelPerez.Taringa.PostEdit {
	public class PEPropertyBox : Control {
		private Dictionary<string, string> _SelectedPropertyModel = null;
		private object _SelectedObject = null;
		private static VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Button.PushButton.Normal);

		public Dictionary<string, string> SelectedPropertyModel {
			get { return _SelectedPropertyModel; }
		}

		public object SelectedObject {
			get { return _SelectedObject; }
		}

		public void ChangeSelectedObject(object obj) {
			try {
				_SelectedObject = obj;
				_SelectedPropertyModel = ((IPEPropertyModelObject)obj).PropertyModel;

				RebuildUi();
			} catch {
#if DEBUG && HEAVY_DEBUG
				throw new Exception("Invalid property model.");
#endif
			}
		}

		public PEPropertyBox() {
			InitializeComponent();
			this.DoubleBuffered = true;
		}

		public void RebuildUi() {
			// Clear all controls.
			this.Controls.Clear();

			// Set back color.
			this.BackColor = Color.FromArgb(248, 248, 248);

			if (_SelectedObject != null) {
				uint propertyCount = 0;

				// Create new controls.
				Panel itemSummaryPanel = new Panel();
				itemSummaryPanel.BackColor = Color.FromArgb(240, 240, 240);
				itemSummaryPanel.Size = new Size(0, 56);
				itemSummaryPanel.Dock = DockStyle.Top;
				itemSummaryPanel.Paint += (sender, args) => {
					args.Graphics.DrawLine(new Pen(new SolidBrush(Color.FromArgb(200, 200, 200))), new Point(0, 55), new Point(itemSummaryPanel.Width, 55));
					base.OnPaint(args);
				};

				Label itemSummaryPanelControlName = new Label();
				itemSummaryPanelControlName.Font = new Font(this.Font, FontStyle.Bold);
				itemSummaryPanelControlName.Text = ((Control)_SelectedObject).Name;
				itemSummaryPanelControlName.AutoEllipsis = true;
				itemSummaryPanelControlName.AutoSize = false;
				itemSummaryPanelControlName.Location = new Point(8, 8);
				itemSummaryPanelControlName.Size = new Size(this.Width - 16, 20);
				itemSummaryPanelControlName.ForeColor = Color.FromArgb(32, 32, 32);
				itemSummaryPanelControlName.AutoEllipsis = true;

				Label itemSummaryPanelControlType = new Label();
				itemSummaryPanelControlType.Text = ((Control)_SelectedObject).GetType().Name;
				itemSummaryPanelControlType.AutoEllipsis = true;
				itemSummaryPanelControlType.AutoSize = false;
				itemSummaryPanelControlType.Location = new Point(8, 30);
				itemSummaryPanelControlType.Size = new Size(this.Width - 16, 20);
				itemSummaryPanelControlType.ForeColor = Color.FromArgb(128, 128, 128);
				itemSummaryPanelControlType.AutoEllipsis = true;

				itemSummaryPanel.Controls.Add(itemSummaryPanelControlName);
				itemSummaryPanel.Controls.Add(itemSummaryPanelControlType);

				Panel propertyPanel = new Panel();
				propertyPanel.Dock = DockStyle.Fill;
				propertyPanel.AutoScroll = true;

				foreach (KeyValuePair<string, string> propertyName in SelectedPropertyModel) {
					Point controlPosition = new Point(8, (20 * (int)propertyCount) + 8);

					string friendlyName = propertyName.Value;
					string realName = propertyName.Key;

					Type propertyObjectType = SelectedObject.GetType();
					PropertyInfo property = propertyObjectType.GetProperty(realName);
					Type propertyType = property.PropertyType;

					Label friendlyNameLabel = new Label();
					friendlyNameLabel.Text = friendlyName;
					friendlyNameLabel.ForeColor = Color.FromArgb(128, 128, 128);
					friendlyNameLabel.AutoSize = false;
					friendlyNameLabel.Size = new Size(100, 20);
					friendlyNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
					friendlyNameLabel.Location = controlPosition;

					if (propertyType == typeof(string)) {
						LinkLabel2 editLink = new LinkLabel2();
						editLink.Text = "Editar...";
						editLink.Location = new Point(116, controlPosition.Y + 3);
						editLink.Click += (sender, args) => {
							TextEditWindow editWindow = new TextEditWindow((PELabel)_SelectedObject);
							editWindow.ShowDialog(this);
						};
						propertyPanel.Controls.Add(editLink);
					} else if (propertyType == typeof(Int64) ||
										 propertyType == typeof(UInt64) ||
										 propertyType == typeof(Int32) ||
										 propertyType == typeof(UInt32) ||
										 propertyType == typeof(Int16) ||
										 propertyType == typeof(UInt16)) {
						NumericUpDown numberEditor = new NumericUpDown();
						numberEditor.Value = (decimal)property.GetValue(SelectedObject, null);
						numberEditor.Size = new Size(this.Width - (16 + friendlyNameLabel.Width), 20);
						numberEditor.Location = controlPosition;
						propertyPanel.Controls.Add(numberEditor);
					} else if (propertyType == typeof(Color)) {
						Color color = ((Color)property.GetValue(SelectedObject, null));
						Panel colorSelectionPanel = new Panel();
						Panel colorPreviewPanel = new Panel();
						LinkLabel2 editLink = new LinkLabel2();
						colorSelectionPanel.Location = new Point(116, controlPosition.Y + 1);
						colorSelectionPanel.Size = new Size(this.Width - (16 + friendlyNameLabel.Width), 20);
						colorPreviewPanel.Location = new Point(2, 2);
						colorPreviewPanel.Size = new Size(16, 16);
						colorPreviewPanel.Paint += (sender, args) => {
							args.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
							args.Graphics.FillEllipse(new SolidBrush(color), 0, 0, 15, 15);
							args.Graphics.DrawEllipse(new Pen(new SolidBrush(Color.FromArgb(32, 0, 0, 0))), 0, 0, 15, 15);
							base.OnPaint(args);
						};

						editLink.Location = new Point(22, 2);
						editLink.Text = String.Format("{0}, {1}, {2}", color.R, color.G, color.B);
						editLink.Click += (sender, args) => {
							ColorSelectionWindow dialog = new ColorSelectionWindow();

							if (dialog.ShowDialog(this) == DialogResult.OK) {
								property.SetValue(SelectedObject, dialog.SelectedColor, null);
								RebuildUi();
							}

							base.OnClick(args);
						};

						colorSelectionPanel.Controls.Add(editLink);
						colorSelectionPanel.Controls.Add(colorPreviewPanel);
						propertyPanel.Controls.Add(colorSelectionPanel);
					} else if (propertyType == typeof(Image)) {
						PictureBox imagePreview = new PictureBox();
						LinkLabel2 editLink = new LinkLabel2();
						imagePreview.BackColor = Color.White;
						imagePreview.Paint += (sender, args) => {
							args.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.FromArgb(32, 0, 0, 0))), 0, 0, 15, 15);
							base.OnPaint(args);
						};
						imagePreview.Location = new Point(118, controlPosition.Y + 3);
						imagePreview.Size = new Size(16, 16);
						imagePreview.SizeMode = PictureBoxSizeMode.Zoom;
						imagePreview.Image = ((Image)property.GetValue(SelectedObject, null));
						
						editLink.Text = "Editar...";
						editLink.Location = new Point(136, controlPosition.Y + 3);
						propertyPanel.Controls.Add(editLink);

						propertyPanel.Controls.Add(editLink);
						propertyPanel.Controls.Add(imagePreview);
					} else if (propertyType == typeof(Size) || propertyType == typeof(Point)) {
						TextBox editBox = new TextBox();
						object propertyValue = property.GetValue(SelectedObject, null);
						editBox.Text = (propertyType == typeof(Size)) ? ((Size)propertyValue).Width.ToString() + ", " + ((Size)propertyValue).Height.ToString() :
																														((Point)propertyValue).X.ToString() + ", " + ((Point)propertyValue).Y.ToString();
						editBox.Location = new Point(116, controlPosition.Y + 3);
						editBox.Size = new Size(this.Width - (32 + friendlyNameLabel.Width), 20);
						editBox.BorderStyle = BorderStyle.None;
						editBox.BackColor = Color.FromArgb(248, 248, 248);
						editBox.ForeColor = Color.FromArgb(96, 96, 96);
						editBox.TextChanged += (sender, args) => {
							try {
								string[] splitValue = editBox.Text.Split(',', ';', '.', ' ');
								object value = ((propertyType == typeof(Size)) ? (object)new Size(int.Parse(splitValue[0]), int.Parse(splitValue[1])) : (object)new Point(int.Parse(splitValue[0]), int.Parse(splitValue[1])));
								property.SetValue(SelectedObject, value, null);
								editBox.ForeColor = Color.FromArgb(96, 96, 96);
							} catch {
								editBox.ForeColor = Color.FromArgb(200, 64, 64);
							}

							base.OnTextChanged(args);
						};

						propertyPanel.Controls.Add(editBox);
					} else {
						// Type is not supported.
						Label unsupportedTypeLabel = new Label();
						unsupportedTypeLabel.Text = "(No soportado)";
						unsupportedTypeLabel.AutoSize = true;
						unsupportedTypeLabel.ForeColor = Color.FromArgb(200, 200, 200);
						unsupportedTypeLabel.Location = new Point(116, controlPosition.Y + 3);
						propertyPanel.Controls.Add(unsupportedTypeLabel);
					}

					propertyPanel.Controls.Add(friendlyNameLabel);

					propertyCount++;
				}

				// Add new controls.
				this.Controls.Add(itemSummaryPanel);
				this.Controls.Add(propertyPanel);

				// Adjust controls.
				propertyPanel.BringToFront();
			} else {
				Label noPropertiesToShowLabel = new Label();
				noPropertiesToShowLabel.Name = "nptsl";
				noPropertiesToShowLabel.ForeColor = Color.FromArgb(128, 128, 128);
				noPropertiesToShowLabel.Text = "No hay propiedades para mostrar.";
				noPropertiesToShowLabel.AutoSize = false;
				noPropertiesToShowLabel.Dock = DockStyle.Fill;
				noPropertiesToShowLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;

				this.Controls.Add(noPropertiesToShowLabel);
			}
		}

		public void InitializeComponent() {
			RebuildUi();
		}
	}
}
